/*
 * string_enh.js
 *
 * Copyright (C) 2006 - OS3 srl - http://www.os3.it
 *
 * Written by: Fabio Rotondo - fabio.rotondo@os3.it
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation;
 * version 2 of the License ONLY.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * NOTE: this is the GPL version of the library. If you want to include this 
 *       library inside a CLOSED SOURCE / PROPRIETARY software, you need 
 *       to purchase a COMMERCIAL LICENSE. See http://www.os3.it/license/
 *       for more info.
 *
 *  2011-04-03: Fix htmlEntities now skips "$"
 *  2009-07-09: Fix htmlEntities now skips ";" "="
 *  2009-06-16: Fix htmlEntities now works again and skips "<" ">", '"', "'", "\r", "\n"
 *  2009-04-16: Fix htmlEntities RegExp to skip "-", "(" and ")"
 *  2009-01-14:	Added the String.buffer class
 */

// PUBLIC: startsWith
String.prototype.startsWith = function ( str )
{
	if ( this.substr ( 0, str.length ) == str ) return ( true );
	
	return ( false );
};

// PUBLIC: endsWith
String.prototype.endsWith = function ( str )
{
	if ( this.substr ( this.length - str.length ) == str ) return ( true );
	
	return ( false );
};

// PUBLIC: buffer
String.buffer = function ()
{
	this._buf = [];

	this.add = function ()
	{
		var t, l = arguments.length;

		for ( t = 0; t < l; t ++ )
		{
			if ( arguments [ t ] && arguments [ t ].length )
			{
				this._buf.push ( arguments [ t ] );
			}
		}

		return this;
	};

	this.get = function ( sep )
	{
		if ( ! sep ) sep = "";

		return this._buf.join ( sep );
	};

	this.length = function () { return this._buf.length; };

	this.clear = function () { this._buf = []; };

	this.toString = function () { return this.get ( "" ); };
};

String._re_htmlentities_invalid = /([^a-zA-Z0-9,.:;=!?+\/_ |@-\\(\\)<>\n\r'"&#{}\[\]$-])/g;
String.prototype.htmlEntities = function ()
{
        function _ch ( m )
        {
                return ( "&#" + m.charCodeAt ( 0 ) + ";" );
        }

        return this.replace ( String._re_htmlentities_invalid, _ch );
};

String._re_entities_decl = /&#([^;]*);/g;
String.prototype.entities2char = function ()
{
	function _ch ( m, p1 )
	{
		return String.fromCharCode ( parseInt ( p1, 10 ) );
	}

	return this.replace ( String._re_entities_decl, _ch );
};


// PUBLIC: join
String.prototype.join = function ( arr )
{
	var l = arr.length;
	var k, t;
	var s = '';
	var is_first = true;

	for ( t = 0; t < l; t ++ )
	{
		if ( typeof ( arr [ t ] ) == 'function' ) continue;
		if ( ! is_first ) s += this;
		s += arr [ t ];
		is_first = false;
	}

	return s;
};

// PUBLIC: lstrip
String.prototype.LStrip = function () { console.warn ( "String.LStrip() is deprecated, use lstrip() instead." ); return this.lstrip (); }; 
String.prototype.lstrip = function () { return this.replace ( /^\s+/, "" ); };

// PUBLIC: rstrip
String.prototype.RStrip = function () { console.warn ( "String.RStrip() is deprecated, use rstrip() instead." ); return this.rstrip (); }; 
String.prototype.rstrip = function () { return this.replace ( /\s+$/, "" ); };

// PUBLIC: strip
String.prototype.Strip = function () { console.warn ( "String.Strip() is deprecated, use strip() instead." ); return this.strip (); }; 
String.prototype.strip = function () { return this.replace ( /^\s+|\s+$/g,"" ); };

// PUBLIC: isUpper
String.prototype.isUpper = function () 
{
	var l = this.length;
	var c, t;

	if ( ! l ) return false;

	for ( t = 0; t < l; t ++ )
	{
		c = this [ t ].toUpperCase ();
		if ( c != this [ t ] ) return false;
	}

	return true;
	
};

// PUBLIC: isLower
String.prototype.isLower =  function () 
{
	var l = this.length;
	var c, t;

	if ( ! l ) return false;

	for ( t = 0; t < l; t ++ )
	{
		c = this [ t ].toLowerCase ();
		if ( c != this [ t ] ) return false;
	}

	return true;
	
};

String.prototype.striphtml = function ()
{
	return this.replace ( /<[^>]*>?/g, '' );
};

String.basename = function ( s, sep )
{
	if ( ! sep ) sep = "/";

	return s.split ( sep ).slice ( -1 );
};

String.dirname = function ( s, sep )
{
	if ( ! sep ) sep = "/";

	return sep.join ( ( s.split ( sep ) ).slice ( 0, -1 ) );
};

// PUBLIC: format
String.format = function ()
{
	function re_replace ( v )
	{
		var m = v.match ( _re_replace );
		var val = args [ ++count ];

		return _string_re_replace ( m, val );
	}

	var _re_replace = /%([0+#-]*)([0-9]*)(\.{0,1})([0-9]*)([dsqm])/;
	var re = /%[0+#-]*[0-9]*\.{0,1}[0-9]*[dsqm]/gi;
	var fmt = arguments [ 0 ];	// The first param is the string format
	var count = 0;
	var args = arguments;

	return fmt.replace ( re, re_replace );
};

// PUBLIC: formatDict
String.formatDict = function ( fmt, dct )
{
	if ( ! dct ) dct = {};
	function re_replace ( v )
	{
		var m = v.match ( _re_replace );
		var kname = m [ 1 ];
		var val = dct [ kname ];
		var p1 = m.shift ();

		if ( typeof ( val )  == 'undefined' )
		{
			var msg = "String.formatDict - Missing parameter: '" + kname + "'";
			if ( console.groupCollapsed )
				console.groupCollapsed ( msg );
			else
				console.group ( msg );
			console.warn ( "Missing parameter: %s info: %o", kname, { "format" : fmt, "dict" : dct } );
			console.trace ();
			console.groupEnd ();

			val = '';
		}

		m.shift ();
		m.unshift ( p1 );
		return _string_re_replace ( m, val );
	}

	var _re_replace = /%\(([^)]*)\)([0+#-]*)([0-9]*)(\.{0,1})([0-9]*)([dsqm])/;
	var re = /%\([a-z0-9_-]+\)[0+#-]?[0-9]*\.?[0-9]*[dsqm]/gi;

	if ( fmt == "" ) return "";

	if ( ! fmt )
	{
		console.warn ( "No FMT for the following dict: %o", dct );

		return "";
	}
	
	return fmt.replace ( re, re_replace );
};

function _string_re_replace ( matches,  value )
{
	var flags = matches [ 1 ];
	var width = ( matches [ 2 ] ? parseInt ( matches [ 2 ] ) : 0 );
	var precision = ( matches [ 4 ] ? parseInt ( matches [ 4 ] ) : 0 );
	var type = matches [ 5 ];
	var res = '';
	var pad_char = ' ';
	var pad_left = false;
	var show_sign = false;

	if ( flags.indexOf ( '-' ) >= 0 ) pad_left = true;
	if ( flags.indexOf ( '0' ) >= 0 ) pad_char = '0';
	if ( flags.indexOf ( '+' ) >= 0 ) show_sign = true;

	if ( pad_char == '0' && pad_left ) pad_char = ' ';

	switch ( type )
	{
		case 'm':	// Money
			if ( typeof ( Money ) != 'undefined' )
			{
				res = Money.fromLongInt ( value );
			} else
				res = value;

			break;
			
		case 'd':
			res  = _string_mkpad ( true, value, precision, width, pad_char, false, pad_left, show_sign );
			break;

		case 'q':
			value = value.replace ( /'/g, "\\'" );
			// Non mettere break, deve finire al case 's'

		case 's':
			res  = _string_mkpad ( false, value, precision, width, pad_char, true, pad_left, false );
			break;
	}

	return res;
}

function _string_mkpad ( is_num, v, prec, width, pad_char, trunc, pad_left, show_sign )
{
	var sign = '';

	if ( is_num )
	{
		v = parseInt ( v, 10 );
		if ( v < 0 ) sign = '-';
		else if ( show_sign ) sign = '+';

		v = Math.abs ( v );
	}

	v = String ( v );

	if ( ! width && ! prec ) return v;

	var len, t, i;

	if ( is_num )
	{
		len = prec - v.length;
		if ( len > 0 ) for ( t = 0; t < len; t ++ ) v = "0" + v;
	}

	v = sign + v;

	len = width - v.length;
	if ( len > 0 )
	{
		for ( t = 0; t < len; t ++ )
			v = ( pad_left ? v + pad_char : pad_char + v );
	}

	if ( ! is_num && prec )
	{
		return v.slice ( 0, prec );
	}

	return  v;
}

